home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 101_01 / life.c < prev    next >
Text File  |  1985-11-13  |  8KB  |  369 lines

  1.  
  2. /*
  3.     "LIFE"
  4.  
  5.     The game invented by John Conway
  6.  
  7.     This version written by Leor Zolman to exemplify
  8.     PROPER use of"goto" statements in C programs!
  9.  
  10.     Note that the Universe is a toroid; i.e,
  11.     the left extreme is adjacent to the right extreme,
  12.     the top is adjacent to the bottom, and each corner
  13.     is adjacent to each other corner.
  14.     In other words, there ARE NO EXTREMES !!
  15.     Or, in a more physical illustration: If I could
  16.     take a peek straight ahead through the magical
  17.     eyepiece of an infinitely powerful telescope,
  18.     I'd be able to see the back of my brain-damaged 
  19.     head....that is, of course, assuming no galaxies
  20.     or cats get in the way.
  21.  
  22. */
  23.  
  24. #define CLEARS "\033E"    /* string to clear the screen on
  25.                your terminal (Escape E does it
  26.                on mine. I strongly feel the
  27.                Heathkit/Zenith H19 terminal is
  28.                the best buy in the market for
  29.                serial console terminals.
  30.                Gratuitous plug ends.)
  31.                                 */
  32. #define TWIDTH 80    /* # of columns on your terminal    */
  33. #define XSIZE 60    /* length of cell array    (max # of lines)*/
  34. #define YSIZE 79    /* width of cell (terminal width - 1)    */
  35.             /* To see how the toroid works,
  36.                try reducing XSIZE and YSIZE to
  37.                around 10 or 20.            */
  38.  
  39. #define BOREDOM_THRESHOLD 5  /* This is how many generations
  40.                 are allowed to pass without a
  41.                 population change before Divine 
  42.                 intervention is called for.    */
  43.  
  44. char *gets();        /* routine to accept a line of input    */
  45. char cell[XSIZE][YSIZE];     /* the universe matrix        */
  46. int minx, maxx, miny, maxy, pop, gen;    /* misc. variables    */
  47. char doneflag;          /* This goes true when we want to stop    */
  48. int boring;        /* keeps count of how many generations
  49.                go by without a population change    */
  50. char center;        /* 1 = center display; 0 = left
  51.                            justify    */
  52. /*
  53.     The main driving routine, to accept random initial
  54.     and population configurations, and display their
  55.     evolution according to a proximity-based formula.
  56. */
  57.  
  58. main()
  59. {
  60.     char c;
  61.     printf("%s\n\t *** BDS Life ***\n",CLEARS);
  62.     printf("\nDo you wish to have the display centered\n");
  63.     printf(" (and thereby slowed down a bit) (y/n) ?");
  64.     center = toupper(getchar()) == 'Y';
  65.     putchar('\n');
  66.  
  67.     for (;;) {
  68.       clear();
  69.       setup();
  70.       if (!pop) break;
  71.       adjust();
  72.       display();
  73.       while (pop) {
  74.         adjust();
  75.         dogen();
  76.         if (kbhit()) {
  77.             getchar();
  78.             printf("\nThe Wrath Of God Strikes!!!!! KA-BEEP!\7\n");
  79.             break;
  80.          }
  81.         display();
  82.         if (boring == BOREDOM_THRESHOLD) {
  83.           boring++;
  84.           printf("\nNo change in population for");
  85.           printf(" %d ",BOREDOM_THRESHOLD);
  86.           printf("generations. Abort (y/n) ");
  87.           c = toupper(getchar());
  88.           putchar('\n');
  89.           if (c == 'Y') break;
  90.          }
  91.         if (doneflag) break;
  92.        }
  93.      }
  94.  }
  95.  
  96. /* Initialize the cell matrix to all dead */
  97.  
  98. clear()
  99. {
  100.     setmem(cell,(XSIZE*YSIZE),0);
  101. }
  102.  
  103. /* Get initial set-up from user */
  104.  
  105. setup()
  106. {
  107.     char c;
  108.     int y;
  109.     char string[YSIZE], *ptr;
  110.     y = pop = gen = minx = maxx = miny= maxy = 0;
  111.     boring = 0;
  112.     printf("\nEnter initial configuration (single period to end):\n");
  113.  
  114.     while (*gets(string) != '.') {
  115.         ptr = string;
  116.         while (*ptr) {
  117.             if ( *ptr++ != ' ') {
  118.                 cell[maxx][y] = 10;
  119.                 ++pop;
  120.              }
  121.             ++y;
  122.             if (y==YSIZE) {
  123.              printf("Truncated to %d chars\n",
  124.                  YSIZE); break;
  125.              }
  126.          }
  127.         --y;
  128.         ++maxx;
  129.         if (y>maxy) maxy = y;
  130.         if (maxx==XSIZE) break;
  131.         y = 0;
  132.      }
  133.     --maxx;
  134. }
  135.  
  136. /* Display the current generation */
  137.  
  138. display()
  139. {
  140.     int i,j,k,l,j9;
  141.     char c;
  142.  
  143.     if (!pop) {
  144.         printf("\nLife ends at %d\n",gen);
  145.         return;
  146.      }
  147.     if(minx && prow(minx-1)) minx--;
  148.     if(miny && pcol(miny-1)) miny--;
  149.     if ((maxx < (XSIZE-1)) && prow(maxx+1)) maxx++;
  150.     if((maxy<(YSIZE-1)) && pcol(maxy+1))maxy++;
  151.     
  152.     while (!prow(minx)) minx++;
  153.     while (!prow(maxx)) maxx--;
  154.     while (!pcol(miny)) miny++;
  155.     while (!pcol(maxy)) maxy--;
  156.  
  157.     puts(CLEARS);
  158.     if (center) {
  159.         i = (TWIDTH-33)/2;
  160.         for (j = 0; j<i; j++) putchar(' ');
  161.     }
  162.     printf("generation = %1d   population = %1d\n",
  163.         gen,pop);
  164.     ++gen;
  165.  
  166.     j9 = maxy - miny + 1;
  167.     for (i = minx; i<=maxx; i++) {
  168.         if (center && j9<TWIDTH) {
  169.             l = (TWIDTH-j9)/2;
  170.             for (k = 0; k<l; k++) putchar(' ');
  171.          }
  172.         for (j=miny; j<=maxy; j++)
  173.             putchar(cell[i][j] ? '*' : ' ');
  174.         if (i != maxx) putchar('\n');
  175.     }
  176. }
  177.  
  178. /* Test if given column is populated */
  179.  
  180. pcol(n)
  181. {
  182.     int i,hi;
  183.     hi = (maxx == (XSIZE-1)) ? maxx : maxx+1;
  184.     for (i = minx ? minx-1 : minx; i<=hi; ++i)
  185.         if (cell[i][n]) return 1;
  186.     return 0;
  187. }
  188.  
  189. /* Test if given row is populated */
  190.  
  191. prow(n)
  192. {
  193.     int i,hi;
  194.     hi = (maxy == (YSIZE-1)) ? maxy : maxy+1;
  195.     for (i = miny ? miny-1 : miny; i<=hi; ++i)
  196.         if (cell[n][i]) return 1;
  197.     return 0;
  198. }
  199.  
  200.  
  201. /*
  202.    Compute next generation. Algorithm used is a two-pass
  203.    cuteness suggested to me by Ward Christensen (he uses
  204.    it on a machine-language version on a 1024 character
  205.    display, and it cranks out 20 generations a second at
  206.    2 MHz.)
  207.    The algorithm uses the low order 3 bits of each 1-byte
  208.    cell as a neighbor count. The first pass finds all live
  209.    cells and increments the count of each of the 8 neighbors
  210.    of such live cells. For the first pass, dead cells are
  211.    totally ignored. The second pass then comes along and
  212.    checks the counts off all cells within the active square
  213.    to determine who lives and who dies. Note that this is a
  214.    significant improvement over the "obvious" method of
  215.    examining all 8 neighbors of each and every cell, dead
  216.    or alive, in the array.
  217. */
  218.  
  219. dogen()
  220. {
  221.     int i,j,i2,j2;
  222.     int bigflag;
  223.     int k,l;
  224.     int oldpop;
  225.     char c;
  226.     int pass;
  227.     doneflag = 1;
  228.     oldpop = pop;
  229.     bigflag =  (minx<2 || maxx>(XSIZE-3) ||
  230.         miny<2 || maxy>(YSIZE-3)) ;
  231.     i2 = (maxx==(XSIZE-1)) ? maxx : maxx+1;
  232.     j2 = (maxy==(YSIZE-1)) ? maxy : maxy+1;
  233.     for (pass = 0; pass < 2; pass++)
  234.     for (i=minx ? minx-1 : minx; i<=i2; ++i)
  235.       for (j=miny ? miny-1 : miny; j<=j2; ++j) {
  236.        c = cell[i][j];
  237.        if (!pass) {
  238.          if (c >= 10)
  239.         if (bigflag)
  240.           for (k = -1; k <= 1; k++)
  241.            for (l = -1; l <= 1; l++)
  242.             cell[mod(i+k,XSIZE)][mod(j+l,YSIZE)]++;
  243.         else
  244.           for (k = -1; k<=1; k++)
  245.            for (l = -1; l <= 1; l++)
  246.             cell[i+k][j+l]++;
  247.         }
  248.        else
  249.          if (c > 10)
  250.         if (c < 13 || c > 14) {
  251.             cell[i][j] = 0;
  252.             pop--;
  253.             doneflag = 0;
  254.          }
  255.         else cell[i][j] = 10;
  256.          else
  257.         if (c == 3) {
  258.             cell[i][j] = 10;
  259.             pop++;
  260.             doneflag = 0;
  261.          }
  262.         else cell[i][j] = 0;
  263.      }
  264.     if (pop == oldpop) boring++;
  265.       else boring = 0;
  266. }
  267.  
  268.  
  269. int mod(a,b)
  270. {
  271.     if (a<0) return b+a;
  272.     if (a<b) return a;
  273.     return a-b;
  274. }
  275.  
  276.  
  277. /* If we're about to run off the matrix, adjust accordingly (if possible) */
  278.  
  279. adjust()
  280. {
  281.     adjx();        /* for overflow in x direction    */
  282.     adjy();        /* and also in y direction    */
  283. }
  284.  
  285. /* Adjust vertical position */
  286.  
  287. adjx()
  288. {
  289.     int delta, i,j;
  290.     int savdelta;
  291.     if (maxx - minx + 1 > XSIZE-2) return;
  292.     if (minx==0) {
  293.         delta = (XSIZE-maxx)/2+maxx;
  294.         savdelta = delta;
  295.         for (i=maxx; i >= 0; --i) {
  296.             for (j=miny; j<=maxy; ++j) {
  297.                 cell[delta][j] = cell[i][j];
  298.                 cell[i][j] = 0;
  299.              }
  300.         --delta;
  301.         }
  302.         minx = delta+1;
  303.         maxx = savdelta;
  304.     }
  305.  
  306.     if (maxx == (XSIZE-1)) {
  307.         delta = minx/2;
  308.         savdelta = delta;
  309.         for (i=minx; i<XSIZE; ++i) {
  310.             for (j=miny; j<=maxy; ++j) {
  311.                 cell[delta][j] = cell[i][j];
  312.                 cell[i][j] = 0;
  313.             }
  314.         ++delta;
  315.         }
  316.         maxx = delta-1;
  317.         minx = savdelta;
  318.     }
  319. }
  320.  
  321.  
  322. /* Adjust horizontal position */
  323.  
  324. adjy()
  325. {
  326.     int delta, i, j;
  327.     int savdelta;
  328.     if (maxy - miny + 1 > YSIZE -2) return;
  329.     if (miny == 0) {
  330.         delta = (YSIZE-maxy)/2+maxy;
  331.         savdelta = delta;
  332.         for (i=maxy; i>=0; --i) {
  333.             for (j=minx; j<=maxx; ++j) {
  334.                 cell[j][delta] = cell[j][i];
  335.                 cell[j][i] = 0;
  336.             }
  337.         --delta;
  338.         }
  339.         miny = delta+1;
  340.         maxy = savdelta;
  341.     }
  342.  
  343.     if (maxy == (YSIZE-1)) {
  344.         delta = miny/2;
  345.         savdelta = delta;
  346.         for (i=miny; i<YSIZE; ++i) {
  347.             for (j=minx; j<=maxx; ++j) {
  348.                 cell[j][delta] = cell[j][i];
  349.                 cell[j][i] = 0;
  350.             }
  351.         ++delta;
  352.         }
  353.         maxy = delta -1;
  354.         miny = savdelta;
  355.     }
  356. }
  357.  
  358. /*
  359.     This is done so that the Wrath Of God doesn't mess up the
  360.     display:
  361. */
  362.  
  363. putchar(c)
  364. char c;
  365. {
  366.     putch(c);